Testy jednostkowe
============

Ponieważ framework testujący w Yii zbudowany jest na bazie [PHPUnit](http://www.phpunit.de/), 
zalecane jest wcześniejsze przejrzenie [dokumentacji PHPUnit](http://www.phpunit.de/manual/current/en/index.html) 
w celu uzyskania podstawowej wiedzy o pisaniu testów jednostkowych. 
Poniżej podsumowujemy podstawowe zasady pisania testów jednostkowych w Yii:

 * Test jednostkowy napisany jest w postaci  klasy `XyzTest`, która dziedziczy z [CTestCase] 
 lub [CDbTestCase], gdzie `Xyz` oznacza klasę, która będzie testowana. Na przykład,
 aby przetestować klasę postu `Post`, nazwiemy odpowiadający jej test umownie `PostTest`. 
 Klasa bazowa [CTestCase] przeznaczona jest dla ogólnych testów jednostkowych, 
 zaś klasa [CDbTestCase] jest bardziej odpowiednia dla testowania klas modeli 
 [rekordu aktywnego](/doc/guide/database.ar). Ponieważ  `PHPUnit_Framework_TestCase` 
 jest klasą rodzica dla obu klas, możemy używać wszystkich metod dziedziczonych z tej klasy.

 * Klasa testu jednostkowego jest zapisana w pliku PHP o nazwie `XyzTest.php`. 
 Zgodnie z przyjętą konwencją plik testu jednostkowego może zostać zapisany 
 w katalogu `protected/tests/unit`.

 * Klasa testująca zawiera głównie zestaw metod nazwanych wg wzorca `testAbc`, gdzie `Abc` 
 często jest nazwą testowanej metody klasy.

 * Metoda testująca zazwyczaj zawiera sekwencję wyrażeń z asercjami (np. `assertTrue`, 
 `assertEquals`), które służą jako punkty kontrolne podczas sprawdzania zachowania 
 obiektu klasy.

W dalszej części opiszemy przede wszsytkim jak pisać testy jednostkowe dla klas modeli 
[rekordu aktywnego](/doc/guide/database.ar). Będziemy rozszerzać nasze klasy testujące 
dziedzicząc z klasy [CDbTestCase] gdyż dostarcza ona wsparcia dla konfiguracji testów bazodanowych, 
o której pisaliśmy w poprzednim rozdziale.

Załóżmy, że chcemy przetestować klasę modelu komentarza `Comment` z
[przykładowego blogu](http://www.yiiframework.com/demos/blog/). Rozpoczynamy poprzez 
utworzenie klasy o nazwie `CommentTest` i zapisania jej jako `protected/tests/unit/CommentTest.php`:

~~~
[php]
class CommentTest extends CDbTestCase
{
	public $fixtures=array(
		'posts'=>'Post',
		'comments'=>'Comment',
	);

	......
}
~~~

W klasie tej, określamy zmienną `fixtures` jako tablicę opisującą konfiguracje 
testów, które będa używane przez ten test. Tablica reprezentuje mapowanie pomiędzy 
nazwami konfiguracji testów a nazwami modeli klas bądź też nazwami konfiguracji 
testów bazodanowych (np. pomiędzy nazwą konfiguracji testu `posts` a klasą modelu `Post`). 
Zauważ, iż podczas mapowania do nazw tabeli konfiguracji testu, poprzedzamy tabelę
dwukropkiem (np. `:Post`) aby odróżnić ją od nazwy klasy modelu. Jeśli będziemy 
używać nazw klas modeli, odpowiadające im tabele będą traktowane jako tabele konfiguracji
testu. Jak już opisaliśmy wcześniej, konfiguracje testu będą zresetowane do jakiegoś znanego 
stanu, za każdym razem, kiedy metoda testowa jest wywoływana.

Nazwy konfiguracji testu pozwalają nam na wygodny dostęp do danych konfiguracji testu w metodach
testujących. Poniższy kod przedstawia ich typowe użycie: 

~~~
[php]
// zwraca wszystkie wiersze z konfiguracji testu dla tabeli komentarzy 'Comment'
$comments = $this->comments;
// zwraca wiersz, którego aliasem jest 'sample1' w konfiguracji testu dla tabeli postów `Post` 
$post = $this->posts['sample1'];
// zwraca instancję AR reprezentującą wiersz danych z konfiguracji testu 'sample1' 
$post = $this->posts('sample1');
~~~

> Note|Uwaga: Jeśli konfiguracja testu została zdefiniowana przy użyciu nazwy tabeli  
(np. `'posts'=>':Post'`), wtedy zaprezetnowany powyżej 3 przykład użycia jest niepoprawny, 
ze względu na to, iż nie posiadamy informacji jaka klasa modelu jest powiązana z tabelą.

W dalszej części opiszemy metodę `testApprove` testującą metodę `approve` w klasie modelu 
komentarza `Comment`. Kod jest bardzo prosty: najpierw wstawiamy komentarz, który
posiada status "oczekujący"; następnie sprawdzamy czy komentarz ten posiada status 
"oczekujący" poprzez odczytanie go z bazy danych; na końcu wołamy metodę `approve` 
i sprawdzamy czy status zmienił tak jak oczekiwaliśmy.

~~~
[php]
public function testApprove()
{
	// wstaw komentarz o statusie "oczekujący"
	$comment=new Comment;
	$comment->setAttributes(array(
		'content'=>'comment 1',
		'status'=>Comment::STATUS_PENDING,
		'createTime'=>time(),
		'author'=>'me',
		'email'=>'me@example.com',
		'postId'=>$this->posts['sample1']['id'],
	),false);
	$this->assertTrue($comment->save(false));

	// zweryfijuj komentarz o statusie "oczekujący"
	$comment=Comment::model()->findByPk($comment->id);
	$this->assertTrue($comment instanceof Comment);
	$this->assertEquals(Comment::STATUS_PENDING,$comment->status);

	// wywołaj metodę approve() i sprawdź czy komentarz znajduje się w statusie "zatwierdzony"
	$comment->approve();
	$this->assertEquals(Comment::STATUS_APPROVED,$comment->status);
	$comment=Comment::model()->findByPk($comment->id);
	$this->assertEquals(Comment::STATUS_APPROVED,$comment->status);
}
~~~

<div class="revision">$Id: test.unit.txt 2841 2011-01-12 21:04:12Z alexander.makarow $</div>